package com.speedchina.permission.web.sys;

import com.speedchina.common.redis.service.RedisService;
import com.speedchina.common.rsa.aop.RequestRSA;
import com.speedchina.common.rsa.resolver.RequestBodyRSA;
import com.speedchina.common.rsa.service.RSAService;
import com.speedchina.framework.helper.Assert;
import com.speedchina.framework.model.R;
import com.speedchina.permission.aspect.SysLog;
import com.speedchina.permission.base.sysenum.UserMsgEnum;
import com.speedchina.permission.base.sysenum.UserStatus;
import com.speedchina.permission.domain.sys.dto.ResourceDTO;
import com.speedchina.permission.domain.sys.entity.User;
import com.speedchina.permission.domain.sys.po.UserPo;
import com.speedchina.permission.properties.SafeProperties;
import com.speedchina.permission.security.jwt.JwtUtil;
import com.speedchina.permission.security.shiro.SecurityUtils;
import com.speedchina.permission.service.sys.ResourceService;
import com.speedchina.permission.service.sys.RoleService;
import com.speedchina.permission.service.sys.SysLogLoginService;
import com.speedchina.permission.service.sys.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 *  菜单管理接口
 * @author winter
 * @date 2021-04-08 15:19:42
 */
@RequestMapping("auth")
@RestController
@Api(description = "系统-权限相关 接口")
@Slf4j
public class HomeController {
    @Autowired
    UserService userService;
    @Autowired
    ResourceService resourceService;
    @Autowired
    RoleService roleService;
    @Autowired
    JwtUtil jwtUtil;
    @Autowired
    SafeProperties safeProperties;
    @Autowired
    RSAService rsaService;
    @Autowired
    RedisService redisService;
    @Value("${speedchina.permission.userLockTime:1800}")
    Long lockTime;
    @Value("${speedchina.permission.userTryLoginNum:5}")
    Integer tryLoginNum;
    @Autowired
    SysLogLoginService logLoginService;
    /**192
     * 获取用户的菜单按钮权限
     * @return
     */
    @ApiOperation("查询用户信息")
    @SysLog("查询用户信息byToken")
    @GetMapping("/userinfo")
    public R userinfo(){
        User user = SecurityUtils.getLoginUser();
        return R.data(userService.getByUserName(user.getUsername()));
    }
    @ApiOperation("查询用户菜单树")
    @SysLog("查询用户信息byToken")
    @GetMapping("/userMenu")
//    @RequiresPermissions("123")
    public R userMenu(){
        User user = SecurityUtils.getLoginUser();
        List<ResourceDTO> list = userService.queryUserMenuTree(user);
        return R.data(list);
    }
    @ApiOperation("查询用户角色、权限集合")
    @SysLog("查询用户角色、权限集合")
    @GetMapping("/permission")
    public R userPermission(){
        User user = SecurityUtils.getLoginUser();
        Set<String> roles = roleService.queryUserRoles(user);
        Map<String,Object> data = new HashMap<>(2);
        data.put("permission",resourceService.getPermissions(user.getId()));
        data.put("roles",roles);
        return R.data(data);
    }
    @GetMapping("/getPublicKey")
    public R getPublicKey() throws Exception {
        Map<String,String> map = rsaService.generatePublicKeyPrivateKey();
        log.debug(map.get("publicKey"));
        log.debug(map.get("privateKey"));
        return R.data(map.get("publicKey"));
    }
    @ApiOperation("管理员重置用户密码")
    @SysLog("管理员重置用户密码")
    @PutMapping("resetPassword")
    @RequestRSA
    public R resetPassword(String username,String password){
        User user = userService.getByUserName(username);
        Assert.isNull(user, UserMsgEnum.USER_NOT_EXIST.getMsg());
        String salt = UUID.randomUUID().toString();
        String newPassword = jwtUtil.passwordEncoder(password,salt);
        return R.data(userService.resetUserPassword(user.getId(),newPassword,salt));
    }
    @ApiOperation("重置用户密码")
    @SysLog("重置用户密码")
    @PutMapping("resetUserPassword")
    @RequestRSA
    public R resetUserPassword(String username,String password,String newPwd){
        User user = userService.getByUserName(username);
        Assert.isNull(user, UserMsgEnum.USERNAME_OR_PASSWORD_ERROR.getMsg());
        ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
        SimpleHash simpleHash = new SimpleHash(safeProperties.getHashAlgorithmName(), password, credentialsSalt, safeProperties.getHashIterations());
        if(!user.getPassword().equals(simpleHash.toString())) {
            return R.error(UserMsgEnum.USERNAME_OR_PASSWORD_ERROR.getMsg());
        }
        String newPassword = jwtUtil.passwordEncoder(newPwd,user.getSalt());
        return R.data(userService.resetUserPassword(user.getId(),newPassword,user.getSalt()));
    }
    @ApiOperation("test")
    @SysLog("test")
    @PutMapping("test")
    @RequestRSA
    public R test(UserPo userPo,String newPwd){
        System.err.println(userPo.getUsername());
        System.err.println(userPo.getPassword());
        return R.ok();
    }
    /**
     * 普通登录入口，支持用户名、密码以及其他验证场景
     * @param model
     * @return
     */
//    @SysLog("登录")
    @ApiOperation("登录")
    @PostMapping("login")
    public R login(@RequestBodyRSA UserPo model) {
        // 正则： 手机号（可走验证码）、邮箱、普通用户名, 目前先支持 普通用户名
        User user = userService.getByUserName(model.getUsername());
        if(user == null) {
            // 迷惑性提示
            return R.error(UserMsgEnum.USERNAME_OR_PASSWORD_ERROR.getMsg());
        }
        if (null == user.getStatus()) {
            return R.error(UserMsgEnum.USER_INFO_EXCEPTION.getMsg());
        } else if (UserStatus.DISABLED.equals(user.getStatus())) {
            return R.error(UserMsgEnum.USER_DISABLE.getMsg());
        } else if (UserStatus.LOCKED.equals(user.getStatus())) {
            return R.error(UserMsgEnum.USER_LOCKING.getMsg());
        }
        if(redisService.get("trylogin_num_"+user.getUsername())!=null){
            int tryNum = Integer.valueOf(redisService.get("trylogin_num_"+user.getUsername()).toString());
            log.debug("{}",tryNum);
            if(tryNum==tryLoginNum){
                redisService.set("trylogin_num_"+user.getUsername(),tryLoginNum+1,lockTime);
                return R.error(UserMsgEnum.USER_LOCKING_30MIN.getMsg());
            }else if(tryNum>tryLoginNum-1){
                return R.error(UserMsgEnum.USER_LOCKING_30MIN.getMsg());
            }
        }
        ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
        SimpleHash simpleHash = new SimpleHash(safeProperties.getHashAlgorithmName(), model.getPassword(), credentialsSalt, safeProperties.getHashIterations());

        try {

            if(user.getPassword().equals(simpleHash.toString())) {
                // 成功登录, 返回用户基本信息、权限标记、菜单信息
                Map<String,Object> data = new HashMap<>(1);
                String jwtToken = jwtUtil.sign(new User(user.getId(), user.getUsername(), user.getPassword()));
                data.put("jwtToken", jwtToken);
                user.setPassword(null);
                data.put("user",user);
                logLoginService.saveSysLogLogin(user,jwtToken);
                return R.data(data);
            } else {
                if(redisService.get("trylogin_num_"+user.getUsername())==null){
                    redisService.set("trylogin_num_"+user.getUsername(),1,lockTime);
                }else {
                    redisService.incr("trylogin_num_"+user.getUsername(),1);
                }
                return R.error(UserMsgEnum.USERNAME_OR_PASSWORD_ERROR.getMsg());
            }
        }catch (Exception e) {
            e.printStackTrace();
            return R.error(e.getMessage());
        }
    }

//    @SysLog("退出登录")
    @ApiOperation("退出登录")
    @PostMapping("logout")
    public R logout() {
        // 考虑做黑名单, 在黑名单（即已经退出的用户）中，则验证token时，做非法处理
//        User user = SecurityUtils.getLoginUser();
        String token;
        try {
            token= SecurityUtils.getToken();
            logLoginService.updateLogLogin(token);
        }catch (Exception e){

        }
        return R.data(SecurityUtils.logout());
    }

    @SysLog("系统-权限 解除用户锁定")
    @ApiOperation("系统-权限 解除用户锁定")
    @PostMapping("unLockUser")
    public R unLockUser(@RequestBodyRSA UserPo model) {
        Assert.isEmpty(model.getUsername(),UserMsgEnum.USERNAME_IS_NOT_BLANK.getMsg());
        if(!redisService.hasKey("trylogin_num_"+model.getUsername())){
            return R.data(true);
        }
        return R.data(redisService.del("trylogin_num_"+model.getUsername()));
    }
}
